Skip to content

Compute the LCL from actual temperature in lfc/el used by cape_cin#4067

Open
gaoflow wants to merge 2 commits into
Unidata:mainfrom
gaoflow:fix/lfc-el-lcl-virtual-temperature
Open

Compute the LCL from actual temperature in lfc/el used by cape_cin#4067
gaoflow wants to merge 2 commits into
Unidata:mainfrom
gaoflow:fix/lfc-el-lcl-virtual-temperature

Conversation

@gaoflow
Copy link
Copy Markdown

@gaoflow gaoflow commented May 27, 2026

Description

Fixes #3857.

cape_cin applies the virtual temperature correction by replacing the environmental
and parcel temperature profiles with their virtual temperatures before calling lfc
and el:

temperature = virtual_temperature_from_dewpoint(pressure, temperature, dewpoint)
parcel_profile = virtual_temperature(parcel_profile, parcel_mixing_ratio)
lfc_pressure, _ = lfc(pressure, temperature, dewpoint, parcel_temperature_profile=parcel_profile, ...)
el_pressure, _ = el(pressure, temperature, dewpoint, parcel_temperature_profile=parcel_profile, ...)

lfc and el then recompute the LCL from those arrayslfc from
parcel_temperature_profile[0], el from temperature[0] — i.e. they treat the
virtual temperature as if it were the actual temperature. Because virtual temperature
is always ≥ temperature, the LCL comes out at too low a pressure (too high an
altitude). Since the LFC and EL are floored at the LCL, both get biased upward; the
effect is strongest on the LFC, exactly as described in the issue.

Fix

Give lfc and el optional lcl_pressure (and, for lfc, lcl_temperature)
keywords so the caller can supply an LCL computed from the actual temperatures. When
the keywords are omitted the LCL is computed from the inputs exactly as before, so
direct callers and the public API are unchanged.

cape_cin already computes the LCL from the actual temperatures (for its below_lcl
mixing-ratio logic) before the virtual-temperature substitution, so it simply passes
that LCL through to lfc/el.

Effect

For a sounding whose LFC is floored at the LCL, the actual-temperature LCL sits about
30–45 hPa higher in pressure than the virtual one, so the LFC (and the CAPE integration
that starts there) is corrected accordingly. For example, on the profile in
test_cape_cin_value_error the surface-based CAPE goes from the previously-reported
2161.9 J/kg to 2206.7 J/kg once the LFC is floored at the correct LCL.

Tests

  • New test_lfc_el_lcl_from_actual_temperature: reconstructs the virtual-temperature
    profiles cape_cin builds and shows that, without the override, lfc floors at the
    spuriously-low virtual LCL, while supplying the actual-temperature LCL floors it at
    the correct LCL (and that el honors the keyword).
  • Updated the expected CAPE in test_cape_cin_value_error (whose LFC is floored at the
    LCL) with a comment explaining the change.

The full tests/calc/test_thermo.py suite passes (228 tests); ruff is clean.

…ta#3857)

cape_cin replaces the environmental and parcel temperature profiles with virtual
temperatures before calling lfc and el. Those functions then recomputed the LCL
from the virtual temperatures, treating virtual temperature as actual temperature.
Because virtual temperature exceeds temperature, the LCL came out at too low a
pressure (too high an altitude), which biased the LFC and EL upward (they are
floored at the LCL).

Add optional lcl_pressure (and, for lfc, lcl_temperature) keywords to lfc and el so
the caller can supply an LCL computed from the actual temperatures. cape_cin already
computes the LCL from the actual temperatures before the virtual-temperature
substitution, so it now passes that LCL through. Direct callers are unaffected: when
the keywords are omitted the LCL is computed as before.

Add a regression test and update the expected CAPE in test_cape_cin_value_error,
whose LFC is floored at the LCL and so increases now that the correct LCL is used.
@gaoflow gaoflow requested a review from a team as a code owner May 27, 2026 21:45
@gaoflow gaoflow requested review from dopplershift and removed request for a team May 27, 2026 21:45
@CLAassistant
Copy link
Copy Markdown

CLAassistant commented May 27, 2026

CLA assistant check
All committers have signed the CLA.

The lfc/el LCL fix changes the surface-based and most-unstable CAPE for the
sounding used in these docstring examples (their LFC is floored at the LCL,
which now sits at the correct, higher pressure), so refresh the expected
doctest output. Verified with the repo's own doctest command
(python -m pytest --doctest-modules -k 'not test' src): 89 passed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Virtual temperature being incorrectly used in lfc and el functions

2 participants